package com.example.mytips.language;

import com.intellij.codeInsight.FileModificationService;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;

import org.jetbrains.annotations.NotNull;

import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CreateLanguage extends AnAction {

    @Override
    public void actionPerformed(@NotNull AnActionEvent e) {
        Project project = e.getProject();
        if (project == null) return;

        Editor editor = e.getData(CommonDataKeys.EDITOR);
        if (editor == null) return;

        // 1) 选中词 + 剪贴板
        String selectedText = editor.getSelectionModel().getSelectedText();
        if (selectedText == null || selectedText.trim().isEmpty()) {
            Messages.showInfoMessage("请先选中一个单词作为方法名。", "提示");
            return;
        }
        String methodName = normalizeAsDartIdentifier(selectedText.trim());

        String clipboardText = getClipboardText();
        if (clipboardText == null || clipboardText.isEmpty()) {
            Messages.showInfoMessage("剪贴板为空。", "提示");
            return;
        }
        String dartLiteral = escapeForDartString(clipboardText);

        // 2) 寻找文件
        String basePath = project.getBasePath();
        if (basePath == null) {
            Messages.showErrorDialog("无法确定工程根目录。", "错误");
            return;
        }
        String path = basePath + "/lib/language/LanguageValue.dart";
        VirtualFile targetFile = LocalFileSystem.getInstance().findFileByPath(path);
        if (targetFile == null) {
            Messages.showErrorDialog("未找到文件：\n" + path, "错误");
            return;
        }

        // 3) 通过 Document 修改（而不是 setBinaryContent）
        FileDocumentManager fdm = FileDocumentManager.getInstance();
        var document = fdm.getDocument(targetFile);
        if (document == null) {
            Messages.showErrorDialog("无法打开 Document（可能不是文本文件）。", "错误");
            return;
        }

        PsiFile psiFile = PsiManager.getInstance(project).findFile(targetFile);
        if (psiFile == null) {
            Messages.showErrorDialog("无法获取 PSI 文件。", "错误");
            return;
        }

        // 确保可写（VCS 只读/只读属性时会弹出解锁/checkout）
        if (!FileModificationService.getInstance().preparePsiElementForWrite(psiFile)) {
            Messages.showErrorDialog("文件不可写。", "错误");
            return;
        }

        // 4) 计算插入位置 & 去重
        String text = document.getText();

        // 简单去重：是否已有同名 static 方法
        Pattern exists = Pattern.compile(
                "\\bstatic\\s+" + Pattern.quote(methodName) + "\\s*\\(",
                Pattern.MULTILINE
        );
        if (exists.matcher(text).find()) {
            Messages.showInfoMessage("已存在同名方法： " + methodName, "提示");
            // 直接把光标定位到已存在的方法上
            int idx = text.indexOf(methodName);
            if (idx >= 0) new OpenFileDescriptor(project, targetFile, idx).navigate(true);
            return;
        }

        // 插入模板方法（缩进用两个空格，交给 reformat 再精修）
        String newMethod =
                "\n  static " + methodName + "(BuildContext context) {\n" +
                        "    return \"" + dartLiteral + "\";\n" +
                        "  }\n";

        // 尝试插到 LanguageValue 类的最后一个花括号前
        int classEnd = lastBraceBeforeClassEnd(text, "LanguageValue");
        if (classEnd < 0) {
            // 兜底：插到文件末尾前的最后一个 '}'
            classEnd = text.lastIndexOf('}');
            if (classEnd < 0) {
                Messages.showErrorDialog("未能定位到类的闭括号，文件格式可能不符合预期。", "错误");
                return;
            }
        }

        int insertOffset = classEnd; // 在 '}' 之前插入

        // 5) 写入 + commit + 格式化 + 保存（全部在 WriteCommandAction 中）
        final int finalInsertOffset = insertOffset;
        WriteCommandAction.runWriteCommandAction(project, () -> {
            document.insertString(finalInsertOffset, newMethod);

            // 提交到 PSI
            PsiDocumentManager.getInstance(project).commitDocument(document);

            // 自动格式化（全文件，最省心；如需更快可只格式化新增范围）
            CodeStyleManager.getInstance(project).reformat(psiFile);

            // 保存到磁盘
            FileDocumentManager.getInstance().saveDocument(document);

            Messages.showInfoMessage("添加成功：" + methodName, "成功");
            new OpenFileDescriptor(project, targetFile, Math.max(0, document.getText().indexOf(methodName))).navigate(true);
        });
    }

    // ==== 辅助方法 ====

    private static String getClipboardText() {
        try {
            return (String) Toolkit.getDefaultToolkit()
                    .getSystemClipboard()
                    .getData(DataFlavor.stringFlavor);
        } catch (Exception e) {
            return null;
        }
    }

    // Dart 标识符：只保留字母/数字/下划线；若首字符是数字则前置下划线
    private static String normalizeAsDartIdentifier(String raw) {
        String s = raw.replaceAll("[^A-Za-z0-9_]", "_");
        if (s.isEmpty()) s = "method";
        if (Character.isDigit(s.charAt(0))) s = "_" + s;
        return s;
    }

    // 转义到 Dart 字符串（最常见情况）
    private static String escapeForDartString(String src) {
        // 只做必要转义：反斜杠和引号、换行
        return src
                .replace("\\", "\\\\")
                .replace("\"", "\\\"")
                .replace("\r\n", "\\n")
                .replace("\n", "\\n")
                .replace("\r", "\\n");
    }

    // 尝试更智能地在 LanguageValue 类闭合花括号前插入
    private static int lastBraceBeforeClassEnd(String text, String className) {
        // 粗略匹配 class LanguageValue { ... }，并找最后一个 }
        Pattern p = Pattern.compile("\\bclass\\s+" + Pattern.quote(className) + "\\b[^{]*\\{", Pattern.MULTILINE);
        Matcher m = p.matcher(text);
        if (!m.find()) return -1;

        int start = m.end(); // 指向 '{' 后
        // 简单的括号计数器，从类开始的 '{' 起算
        int depth = 1;
        for (int i = start; i < text.length(); i++) {
            char c = text.charAt(i);
            if (c == '{') depth++;
            else if (c == '}') {
                depth--;
                if (depth == 0) return i; // 返回类闭合 '}' 的位置
            }
        }
        return -1;
    }
}
